package com.nartosoft.tubuloader;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;


@SuppressWarnings("serial")
public class TubuloaderDialog extends JDialog
{
  private JList tubuloadList;
  private JScrollPane listScroller;

  private JTextField filenameTextField;
  private JButton fileBrowseButton;
  private JTextField titleTextField;
  private JTextArea descriptionTextArea;
  private JComboBox categoryComboBox;
  private JTextField tagTextField;
  private JRadioButton privateVisibilityButton;
  private JRadioButton publicVisibilityButton;

  private JButton applyCategoryToAllButton;
  private JButton applyDescriptionToAllButton;
  private JButton applyTagsToAllButton;
  private JButton applyTitleToAllButton;
  private JButton applyVisibilityToAllButton;

  private TubuloadModel model;

  private InputController inputControler;

  private Tubuload currentTubuload;

  public TubuloaderDialog(List<String> filenames) {
    model = new TubuloadModel();
    inputControler = new InputController();

    setTitle("Tubuloader 0.1 GUI prototype");

    if (filenames.isEmpty()) {
      throw new IllegalArgumentException("no filenames specified");
    }

    createModel(filenames);
    initComponents();
    setMultiUploadWidgetsVisible(model.getSize() != 1);
    tubuloadList.setSelectedIndex(0);
    this.pack();
    this.setLocationRelativeTo(null);//centers on screen
  }

  public List<Tubuload> getTubuloads() {
    return model.getTubuloads();
  }

  //----- List of Tubuloads -----

  private void createModel(List<String> filenames) {
    model = new TubuloadModel();
    for (String filename : filenames) {
      model.addTubuload(createTubuload(filename));
    }
  }

  private Tubuload createTubuload(String filename) {
    Tubuload data = new Tubuload();
    data.setFilename(filename);
    // TODO: fill with default/recent settings
    return data;
  }

  //----- UI Components -----

  private void initComponents() {
    JPanel rootPanel = new JPanel(new BorderLayout());
    add(rootPanel);

    createList();
    JPanel tubuloadPanel = createTubuloadEditorPanel();
    JPanel mainButtonPanel = createMainButons();

    JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, listScroller, tubuloadPanel);
    rootPanel.add(splitPane, BorderLayout.NORTH);
    rootPanel.add(mainButtonPanel, BorderLayout.SOUTH);
  }

  private void createList() {
    tubuloadList = new JList(model);
    listScroller = new JScrollPane(tubuloadList);

    tubuloadList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    tubuloadList.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        if (tubuloadList.getSelectedIndex() >= 0) {
          setCurrentTubuload((Tubuload)model.getElementAt(tubuloadList.getSelectedIndex()));
        }
      }
    });
  }

  private JPanel createMainButons() {
    JButton cancelButton = new JButton("Cancel");
    JButton uploadButton = new JButton("Upload");

    cancelButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
        model.clear();
      }
    });

    uploadButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
      }
    });

    JPanel buttonPanel = new JPanel();
    buttonPanel.add(cancelButton);
    buttonPanel.add(uploadButton);
    return buttonPanel;
  }

  private void setCurrentTubuload(Tubuload tubuload) {
    if (tubuload == currentTubuload) {
      return;
    }

    this.currentTubuload = tubuload;

    filenameTextField.setText(tubuload.getFilename());
    titleTextField.setText(tubuload.getTitle());
    descriptionTextArea.setText(tubuload.getDescription());
    categoryComboBox.setSelectedItem(tubuload.getCategory());
    tagTextField.setText(tubuload.getTags());
    publicVisibilityButton.setSelected(tubuload.isPublic());
    privateVisibilityButton.setSelected(!tubuload.isPublic());
  }

  private JPanel createTubuloadEditorPanel() {
    JPanel tubuloadPanel = new JPanel(new GridBagLayout());
    JPanel filePanel = createFilenameInput();
    createTitleInput();
    JScrollPane descriptionTextScrollArea = createDescriptionInput();
    createCategoryInput();
    createTagInput();
    JPanel visibilityPanel = createVisibilityInput();
    createApplyToAllButtons();

    tubuloadPanel.add(new JLabel("File"), createConstraints(0, 0));
    tubuloadPanel.add(new JLabel("Title"), createConstraints(0, 1));
    tubuloadPanel.add(new JLabel("Description"), createTopAnchoredConstraints(0, 2));
    tubuloadPanel.add(new JLabel("Category"), createConstraints(0, 3));
    tubuloadPanel.add(new JLabel("Tags"), createConstraints(0, 4));
    tubuloadPanel.add(new JLabel("Visibility"), createConstraints(0, 5));

    tubuloadPanel.add(filePanel, createExpandingConstraints(1, 0));
    tubuloadPanel.add(titleTextField, createExpandingConstraints(1, 1));
    tubuloadPanel.add(descriptionTextScrollArea, createExpandingConstraints(1, 2));
    tubuloadPanel.add(categoryComboBox, createExpandingConstraints(1, 3));
    tubuloadPanel.add(tagTextField, createExpandingConstraints(1, 4));
    tubuloadPanel.add(visibilityPanel, createExpandingConstraints(1, 5));

    tubuloadPanel.add(applyTitleToAllButton, createConstraints(2, 1));
    tubuloadPanel.add(applyDescriptionToAllButton, createTopAnchoredConstraints(2, 2));
    tubuloadPanel.add(applyCategoryToAllButton, createConstraints(2, 3));
    tubuloadPanel.add(applyTagsToAllButton, createConstraints(2, 4));
    tubuloadPanel.add(applyVisibilityToAllButton, createConstraints(2, 5));

    return tubuloadPanel;
  }

  private JPanel createFilenameInput() {
    filenameTextField = new JTextField();
    filenameTextField.getDocument().addDocumentListener(inputControler);
    fileBrowseButton = new JButton("...");
    fileBrowseButton.addActionListener(inputControler);
    JPanel filePanel = new JPanel(new GridBagLayout());
    filePanel.add(filenameTextField, createExpandingConstraints(0, 0));
    filePanel.add(fileBrowseButton, createConstraints(1, 0));
    return filePanel;
  }

  private void createTitleInput() {
    titleTextField = new JTextField();
    titleTextField.getDocument().addDocumentListener(inputControler);
  }

  private JScrollPane createDescriptionInput() {
    descriptionTextArea = new JTextArea(4, 0);
    descriptionTextArea.getDocument().addDocumentListener(inputControler);

    return new JScrollPane(descriptionTextArea);
  }

  private void createCategoryInput() {
    categoryComboBox = new JComboBox();

    for (Category category : Category.getCategories()) {
      categoryComboBox.addItem(category);
    }

    categoryComboBox.addActionListener(inputControler);
  }

  private void createTagInput() {
    tagTextField = new JTextField();
    tagTextField.getDocument().addDocumentListener(inputControler);
  }

  private JPanel createVisibilityInput() {
    publicVisibilityButton = new JRadioButton("Public");
    publicVisibilityButton.addActionListener(inputControler);
    privateVisibilityButton = new JRadioButton("Private");
    privateVisibilityButton.addActionListener(inputControler);

    ButtonGroup visibilityButtonGroup = new ButtonGroup();
    visibilityButtonGroup.add(publicVisibilityButton);
    visibilityButtonGroup.add(privateVisibilityButton);

    JPanel visibilityPanel = new JPanel(new GridBagLayout());
    visibilityPanel.add(publicVisibilityButton, createConstraints(0, 0));
    visibilityPanel.add(privateVisibilityButton, createExpandingConstraints(1, 0));

    return visibilityPanel;
  }

  private void createApplyToAllButtons() {
    applyTitleToAllButton = new JButton("Apply to all");
    applyDescriptionToAllButton = new JButton("Apply to all");
    applyCategoryToAllButton = new JButton("Apply to all");
    applyTagsToAllButton = new JButton("Apply to all");
    applyVisibilityToAllButton = new JButton("Apply to all");

    applyTitleToAllButton.addActionListener(inputControler);
    applyDescriptionToAllButton.addActionListener(inputControler);
    applyCategoryToAllButton.addActionListener(inputControler);
    applyTagsToAllButton.addActionListener(inputControler);
    applyVisibilityToAllButton.addActionListener(inputControler);
  }

  //----- Helper methods for UI -----

  private GridBagConstraints createConstraints(int x, int y) {
    GridBagConstraints c = new GridBagConstraints();
    c.gridx = x;
    c.gridy = y;
    c.fill = GridBagConstraints.HORIZONTAL;
    return c;
  }

  private GridBagConstraints createExpandingConstraints(int x, int y) {
    GridBagConstraints c = createConstraints(x, y);
    c.weightx = 1.0;
    return c;
  }

  private GridBagConstraints createTopAnchoredConstraints(int x, int y) {
    GridBagConstraints c = createConstraints(x, y);
    c.anchor = GridBagConstraints.FIRST_LINE_START;
    return c;
  }

  private void setMultiUploadWidgetsVisible(boolean isVisible) {
    listScroller.setVisible(isVisible);
    applyTitleToAllButton.setVisible(isVisible);
    applyDescriptionToAllButton.setVisible(isVisible);
    applyCategoryToAllButton.setVisible(isVisible);
    applyTagsToAllButton.setVisible(isVisible);
    applyVisibilityToAllButton.setVisible(isVisible);
  }

  // Listener for all widgets on the Tubuload editing pane.
  private class InputController implements ActionListener, DocumentListener {
    public void changedUpdate(DocumentEvent event) {
    }

    public void insertUpdate(DocumentEvent event) {
      updateData(event);
    }

    public void removeUpdate(DocumentEvent event) {
      updateData(event);
    }

    private void updateData(DocumentEvent event) {
      if (event.getDocument() == filenameTextField.getDocument()) {
        if (!currentTubuload.getFilename().equals(filenameTextField.getText())) {
          currentTubuload.setFilename(filenameTextField.getText());
        }
      }
      else if (event.getDocument() == titleTextField.getDocument()) {
        if (!currentTubuload.getTitle().equals(titleTextField.getText())) {
          currentTubuload.setTitle(titleTextField.getText());
        }
      }
      else if (event.getDocument() == descriptionTextArea.getDocument()) {
        if (!currentTubuload.getDescription().equals(descriptionTextArea.getText())) {
          currentTubuload.setDescription(descriptionTextArea.getText());
        }
      }
      else if (event.getDocument() == tagTextField.getDocument()) {
        if (!currentTubuload.getTags().equals(tagTextField.getText())) {
          currentTubuload.setTags(tagTextField.getText());
        }
      }
    }

    public void actionPerformed(ActionEvent event) {
      if (event.getSource() == fileBrowseButton) {
        JFileChooser fileChooser = new JFileChooser(currentTubuload.getFilename());
        fileChooser.showOpenDialog(null);
        File file = fileChooser.getSelectedFile();
        if (file != null) {
          filenameTextField.setText(file.getAbsolutePath());
        }
      }
      else if (event.getSource() == categoryComboBox) {
        currentTubuload.setCategory((Category)categoryComboBox.getSelectedItem());
      }
      else if (event.getSource() == publicVisibilityButton) {
        currentTubuload.setPublic(true);
      }
      else if (event.getSource() == privateVisibilityButton) {
        currentTubuload.setPublic(false);
      }
      else if (event.getSource() == applyTitleToAllButton) {
        for (Tubuload tubuload : model.getTubuloads()) {
          tubuload.setTitle(currentTubuload.getTitle());
        }
      }
      else if (event.getSource() == applyDescriptionToAllButton) {
        for (Tubuload tubuload : model.getTubuloads()) {
          tubuload.setDescription(currentTubuload.getDescription());
        }
      }
      else if (event.getSource() == applyCategoryToAllButton) {
        for (Tubuload tubuload : model.getTubuloads()) {
          tubuload.setCategory(currentTubuload.getCategory());
        }
      }
      else if (event.getSource() == applyTagsToAllButton) {
        for (Tubuload tubuload : model.getTubuloads()) {
          tubuload.setTags(currentTubuload.getTags());
        }
      }
      else if (event.getSource() == applyVisibilityToAllButton) {
        for (Tubuload tubuload : model.getTubuloads()) {
          tubuload.setPublic(currentTubuload.isPublic());
        }
      }
    }
  }
}
